// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.credentialStore.keePass

import com.intellij.credentialStore.EncryptionSpec
import com.intellij.credentialStore.EncryptionType
import com.intellij.credentialStore.kdbx.KdbxPassword
import com.intellij.credentialStore.kdbx.KeePassDatabase
import com.intellij.credentialStore.kdbx.loadKdbx
import com.intellij.testFramework.assertions.Assertions.assertThat
import com.intellij.util.io.delete
import com.intellij.util.io.outputStream
import com.intellij.util.io.readText
import com.intellij.util.io.write
import org.junit.Test
import java.util.*

internal class KeePassFileManagerTest : BaseKeePassFileManagerTest() {
  @Test
  fun `saveMasterKeyToApplyNewEncryptionSpec must respect existing isAutoGenerated flag`() {
    val store = createStore()
    store.save(defaultEncryptionSpec)

    TestKeePassFileManager(store, masterPasswordRequestAnswer = "boo", masterKeyEncryptionSpec = EncryptionSpec(EncryptionType.BUILT_IN, pgpKeyId = null))
      .saveMasterKeyToApplyNewEncryptionSpec()

    assertThat(store.masterKeyFile.readText()).startsWith("""
          encryption: BUILT_IN
          isAutoGenerated: true
          value: !!binary
        """.trimIndent())
  }

  @Test
  fun `use existing with custom master key but key file doesn't exist but user provided new`() {
    val otherStore = createTestStoreWithCustomMasterKey(fsRule.fs.getPath("/other"))
    otherStore.save(defaultEncryptionSpec)
    fsRule.fs.getPath("/other/${MASTER_KEY_FILE_NAME}").delete()

    val masterKeyFile = fsRule.fs.getPath("/").resolve(MASTER_KEY_FILE_NAME)
    val keePassFileManager = TestKeePassFileManager(otherStore.dbFile, masterKeyFile, masterPasswordRequestAnswer = "foo")
    keePassFileManager.useExisting()
    assertThat(keePassFileManager.isUnsatisfiedMasterPasswordRequest).isFalse()
    checkStoreAfterSuccessfulImport(KeePassCredentialStore(dbFile = otherStore.dbFile, masterKeyFile = masterKeyFile))
    assertThat(masterKeyFile).isRegularFile
  }

  @Test
  fun reuseExisting() {
    val dbFile = fsRule.fs.getPath("/existingDb.kdbx")
    @Suppress("SpellCheckingInspection")
    dbFile.write(Base64.getDecoder().decode(
      "A9mimmf7S7UBAAMAAhAAMcHy5r9xQ1C+WAUhavxa/wMEAAEAAAAEIAAWuDmigh57N8BZgj1w0GctkaqFTO7nPOroO5AnmUliFgUgAHCRnuiXHvLqSv2oJPMHI5QS9Ony+oIOww4kHcpz2wmEBgg" +
      "AcBcAAAAAAAAHEAB2bInsMKh/zNzzBaegBa/kCCAAw3NSQcu+oGXwJvY9Ht6NSCC19uGFN+sEP9n9E3tNCvoJIADD/kYwUqnCSzrzYXu3tcJcvBKzTinwcSZQ769wYZ/oPwoEAAIAAAAABAAA0K0" +
      "KdKTDfpMiRxKSe1xkvCDuBDdlDe/hiU3YnkhhCZk48sB9OV4uZI1LPJAgQ8HogjxMjAhnNThYdjlFQ9TTfsb3wUXH/7IK8n69a8IoWuRp9fnchQFnnArXcZeimeUREb/3jcwTXrIHGg+AN7MPQCD/b" +
      "47us2h07oaAVvGFLCaLU111mJNZrdjNvO9BKODUbqfFFVhJhMAazjsdVpRfV3dbm0apdgluJQ8eUFzrF4YZUUkenG869o/yngD2cm1BxmG2QZe2fel/PSWRRFZ0i6zJm3h9CnYStnDL2N6lm9MPqOm3p" +
      "KUk0uOG8p9P4U4UHMOnwIFw4RReO5wnqpMN4DFUCfM1qqx0fuqc/sy3DEgpRg3ENsHU7AbidobJzIqGOeK9ywU6Rp5peJrLjbIszedVWVPvxwt/xgAHcaqfntV86XcG8MlJElLSsK4fh9gspySNeyP43" +
      "wnLjAdFGHq5OtAkhTTwXzHSZTxhazTjClssAHYAyTEQrlYRFl4+4apzdq5g3crGl1vR0Ekj22ytIsQXu9HYVTZ6pk6ESQAIg1qieDZQl4B1eEaRNnyvkfhgPIUDLuG4ULMGm/L1dur2nhHlooqgR8gHo5" +
      "MNclghOKZdOhJNOvsd7/1XDsziizOqbocjJtBCEOWSgI1Ht1fbmG1nO9C6MrzkkxK+xQaXZDG2fmitUw2flN3OMky/RJgMD4LVdZLoaHj3uq86USXjDc0ql7lHeRRmOhIJ3X8DZObJmyhlylBGYwmYB/Pm" +
      "Ouoe28iM8/wQ4Xr8bSYco5kxOK8Bii5TotDXqhVlTdajCo5NN33nqeSc/f+5BGL/CmdxannLel1bnEJrY2ESYXrjzUSM0pgnJlLNxZYynw/XMtSPbXI8/m2ciAP9iXv5efJMOv8O6dmzlbiYz7efSEpIDi" +
      "wHG7HAIVnVzmy26jhyHXchaQpouPnwj/QhzTL1lRv0qA2K5+wNIexkKQa4G4iZhSHVzZTHY12rpnLDTxWv2GXHCvwdY5AD6jTJazimlTpbVOf+UvDIPiY2ksmhnaZU9Lc/ItkInhtZwW0e0XtdcgunaVr5Bv" +
      "HTRRancrtRN23VAUlNzQ7Uror55JG3PxUThOX8XRmqJxMnIlgpNbv/tgqbks7zuCESLFjz0EM19QygatS+uHCWnsUp8sWl14bcrwGRoFsdPj/AFRGAv2xYwfMT8VBOZx1KpQ0vqxOx8t67pxpBUaH/Cqlh8J" +
      "je7vxXT7wrXQK3bVjpk2uYncAkd7ruk0y7X/Jzvyu9cfoEDn6EMOS0b5aE6VoywNHhbo3dGyZq3K25jOGvgLzRSj9ETBNL8DTccaNzkcyXBsj/gqUZ1rYxVZHPaJWi2Cgy07b+jV5FSRSMYkjNG90ADHKnqyuEG1" +
      "Y7+pvIX1hOBGIVJ0HA9Ij6xYTZXkGRu6V+WGYEPnDJ4Pi+EYwD400nxtrxwpGiEHWYzyjACHB2BKS9J3BDh4S/"))

    fun checkEntry(db: KeePassDatabase) {
      assertThat(db.rootGroup.getEntry("foo", "foo")!!.password!!.get().toString()).isEqualTo("bar")
    }

    val kdbxPassword = KdbxPassword("foo".toByteArray())
    var db = loadKdbx(dbFile, kdbxPassword)
    checkEntry(db)

    dbFile.outputStream().use {
      db.save(kdbxPassword, it, SECURE_RANDOM_CACHE.value)
    }

    db = loadKdbx(dbFile, kdbxPassword)
    checkEntry(db)
  }

  @Test
  fun `require custom master password if need - not custom`() {
    val store = createStore()
    store.save(defaultEncryptionSpec)
    TestKeePassFileManager(store, masterPasswordRequestAnswer = "bar42").setCustomMasterPasswordIfNeeded(fsRule.fs.getPath("/someDefault"))
    assertThat(MasterKeyFileStorage(store.masterKeyFile).load()!!.toString(Charsets.UTF_8)).isEqualTo("bar42")
    assertThat(createTestStoreWithCustomMasterKey().get(testCredentialAttributes)!!.password!!.toString()).isEqualTo("p")
  }

  @Test
  fun `require custom master password if need - custom`() {
    val store = createTestStoreWithCustomMasterKey()
    TestKeePassFileManager(store, masterPasswordRequestAnswer = "bar42").setCustomMasterPasswordIfNeeded(fsRule.fs.getPath("/someDefault"))
    assertThat(MasterKeyFileStorage(store.masterKeyFile).load()!!.toString(Charsets.UTF_8)).isEqualTo("foo")
    assertThat(createTestStoreWithCustomMasterKey().get(testCredentialAttributes)!!.password!!.toString()).isEqualTo("p")
  }
}
